package com.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.dao.*;
import com.entity.*;
import com.exception.CustomException;
import com.exception.CustomTransactionalException;
import com.form.examination.AddExaminationFrom;
import com.form.examination.ExamPageForm;
import com.form.examination.ExamRecordPageForm;
import com.form.examination.SubmitExamForm;
import com.vo.Msg;
import com.vo.PageVo;
import com.vo.exam.ExamRecord;
import com.vo.exam.ExamRecordDetail;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Version: V1.0    <br/>
 * Datetime:   2022/5/15 16:34   <br/>
 * Description: 试卷服务
 *
 * @author: chen
 */
@Service
public class ExaminationPaperService {

    @Resource
    private ExaminationPaperMapper examinationPaperMapper;

    @Resource
    private TestPaperQuestionMapper testPaperQuestionMapper;

    @Resource
    private ExamAnswerDetailMapper examAnswerDetailMapper;

    @Resource
    private ExamAnswerRecordMapper examAnswerRecordMapper;

    @Resource
    private TestQuestionMapper testQuestionMapper;


    public int deleteByPrimaryKey(Integer id) {
        return examinationPaperMapper.deleteByPrimaryKey(id);
    }


    public int insert(ExaminationPaper record) {
        return examinationPaperMapper.insert(record);
    }


    public int insertSelective(ExaminationPaper record) {
        return examinationPaperMapper.insertSelective(record);
    }


    public ExaminationPaper selectByPrimaryKey(Integer id) {
        return examinationPaperMapper.selectByPrimaryKey(id);
    }


    public int updateByPrimaryKeySelective(ExaminationPaper record) {
        return examinationPaperMapper.updateByPrimaryKeySelective(record);
    }


    public int updateByPrimaryKey(ExaminationPaper record) {
        return examinationPaperMapper.updateByPrimaryKey(record);
    }

    @Transactional(rollbackFor = CustomTransactionalException.class)
    public boolean createExaminationPaper(AddExaminationFrom addExaminationFrom) {
        addExaminationFrom.setId(null);
        ExaminationPaper examinationPaper = new ExaminationPaper();
        examinationPaper.setName(addExaminationFrom.getName());
        examinationPaper.setExamduration(addExaminationFrom.getExamDuration());
        examinationPaper.setStatus(addExaminationFrom.getStatus());
        examinationPaper.setCreateTime(new Date());
        // 插入试卷
        int insert = examinationPaperMapper.insert(examinationPaper);
        if (insert != 1) {
            throw new CustomTransactionalException("插入试卷失败");
        }
        Date date = new Date();

        List<TestPaperQuestion> paperQuestionList = new LinkedList<>();
        List<Integer> singleChoice = addExaminationFrom.getSingleChoice() != null ? addExaminationFrom.getSingleChoice() : new LinkedList<>();
        for (Integer integer : singleChoice) {
            TestPaperQuestion t = new TestPaperQuestion();
            t.setTestPaperId(examinationPaper.getId());
            t.setCreateTime(date);
            t.setQuestionId(integer);
            paperQuestionList.add(t);
        }
        List<Integer> multipleChoice = addExaminationFrom.getMultipleChoice() != null ? addExaminationFrom.getMultipleChoice() : new LinkedList<>();
        for (Integer integer : multipleChoice) {
            TestPaperQuestion t = new TestPaperQuestion();
            t.setTestPaperId(examinationPaper.getId());
            t.setCreateTime(date);
            t.setQuestionId(integer);
            paperQuestionList.add(t);
        }
        List<Integer> judge = addExaminationFrom.getTrueOrFalse() != null ? addExaminationFrom.getTrueOrFalse() : new LinkedList<>();
        for (Integer integer : judge) {
            TestPaperQuestion t = new TestPaperQuestion();
            t.setTestPaperId(examinationPaper.getId());
            t.setQuestionId(integer);
            t.setCreateTime(date);
            paperQuestionList.add(t);
        }
        List<Integer> fillInTheBlank = addExaminationFrom.getFillInTheBlank() != null ? addExaminationFrom.getFillInTheBlank() : new LinkedList<>();
        for (Integer integer : fillInTheBlank) {
            TestPaperQuestion t = new TestPaperQuestion();
            t.setTestPaperId(examinationPaper.getId());
            t.setQuestionId(integer);
            t.setCreateTime(date);
            paperQuestionList.add(t);
        }
        // 创建试卷和题目的关联
        if (paperQuestionList.size() > 0) {
            int insert2 = testPaperQuestionMapper.insertList(paperQuestionList);
            if (insert2 != paperQuestionList.size()) {
                throw new CustomTransactionalException("插入试卷和题目的关联失败");
            }
        }
        return true;
    }

    @Transactional(rollbackFor = CustomTransactionalException.class)
    public boolean deleteById(Integer id) {
        // 删除试卷
        examinationPaperMapper.deleteByPrimaryKey(id);
        // 删除试卷和题目的关联
        testPaperQuestionMapper.deleteByExaminationPaperId(id);
        // 删除关联该试卷的作答记录
        examAnswerRecordMapper.deleteByExaminationPaperId(id);
        // 删除详细的作答记录
        examAnswerDetailMapper.deleteByExaminationPaperId(id);
        return true;
    }

    public boolean updateExaminationPaper(AddExaminationFrom addExaminationFrom) {
        return deleteById(addExaminationFrom.getId()) && createExaminationPaper(addExaminationFrom);
    }

    public AddExaminationFrom getById(Integer id) {
        // 查询试卷
        ExaminationPaper examinationPaper = examinationPaperMapper.selectByPrimaryKey(id);
        if (examinationPaper == null) {
            throw new CustomException("试卷不存在");
        }
        // 查询试卷和题目的关联
        List<TestPaperQuestion> testPaperQuestionList = testPaperQuestionMapper.selectByExaminationPaperId(id);
        // 提取试题编号
        List<Integer> questionIds = new LinkedList<>();
        for (TestPaperQuestion testPaperQuestion : testPaperQuestionList) {
            questionIds.add(testPaperQuestion.getQuestionId());
        }
        // 查询试题
        List<TestQuestion> questionList = testQuestionMapper.selectByIds(questionIds);
        // 分类
        List<Integer> singleChoice = new LinkedList<>();
        List<Integer> multipleChoice = new LinkedList<>();
        List<Integer> trueOrFalse = new LinkedList<>();
        List<Integer> fillInTheBlank = new LinkedList<>();
        for (TestQuestion t : questionList) {
            if (t.getType() == 1) {
                singleChoice.add(t.getId());
            } else if (t.getType() == 2) {
                multipleChoice.add(t.getId());
            } else if (t.getType() == 3) {
                trueOrFalse.add(t.getId());
            } else if (t.getType() == 4) {
                fillInTheBlank.add(t.getId());
            }
        }
        AddExaminationFrom t = new AddExaminationFrom();
        t.setId(examinationPaper.getId());
        t.setName(examinationPaper.getName());
        t.setExamDuration(examinationPaper.getExamduration());
        t.setStatus(examinationPaper.getStatus());
        t.setSingleChoice(singleChoice);
        t.setMultipleChoice(multipleChoice);
        t.setTrueOrFalse(trueOrFalse);
        t.setFillInTheBlank(fillInTheBlank);
        return t;
    }

    public PageVo<ExaminationPaper> pageList(ExamPageForm examPageForm) {
        PageVo<ExaminationPaper> pageVo = new PageVo<ExaminationPaper>().setCurrentAndSize(examPageForm);
        // 设置总的记录条数
        pageVo.setTotal(counterTotalNumber(examPageForm));
        // 当前查询页数
        int pageIndex = pageVo.getPageIndex();
        // 判断当前页数是否超过总页数
        pageIndex = pageIndex > pageVo.getPages() ? 1 : pageIndex;
        pageVo.setPageIndex(pageIndex);
        // 查询数据
        List<ExaminationPaper> list = examinationPaperMapper.selectByPage((pageIndex - 1) * pageVo.getPageSize(), pageVo.getPageSize(), examPageForm.getName(), examPageForm.getStatus());
        list.forEach(e -> {
            e.setQuestionSize(counterQuestionNumber(e.getId()));
        });
        pageVo.setRecords(list);
        return pageVo;
    }

    private Integer counterQuestionNumber(Integer id) {
        return testPaperQuestionMapper.countByExaminationPaperId(id);
    }

    private Long counterTotalNumber(ExamPageForm examPageForm) {
        return examinationPaperMapper.counterTotalNumber(examPageForm.getName(), examPageForm.getStatus());
    }

    /**
     * 进入考试，会覆盖之前的考试结果
     *
     * @param userId  用户id
     * @param paperId 试卷id
     * @param confirm 是否确认
     * @return 返回考试信息
     */
    public Msg entranceExam(Integer userId, Integer paperId, Boolean confirm) {
        // 查询考试结果
        ExamAnswerRecord examAnswerRecord = examAnswerRecordMapper.selectByUserIdAndPaperId(userId, paperId);
        if (examAnswerRecord != null) {
            // 确认覆盖
            if (confirm) {
                // 删除考试记录
                examAnswerRecordMapper.deleteByPrimaryKey(examAnswerRecord.getId());
                // 删除答题记录
                examAnswerDetailMapper.deleteByExaminationPaperIdAndUserId(userId, paperId);
            } else {
                return Msg.code(0, "考试已经完成，是否覆盖之前的考试结果？");
            }
        } else {
            // 没有考试记录，则直接进入考试
            return Msg.success();
        }
        return Msg.success();
    }

    /**
     * 获取考试内容
     *
     * @param paperId 试卷id
     * @return 返回考试内容
     */
    public Msg getExaminationContent(Integer paperId) {
        // 获取试卷信息
        ExaminationPaper examinationPaper = examinationPaperMapper.selectByPrimaryKey(paperId);
        if (examinationPaper == null) {
            return Msg.error("试卷不存在");
        }
        // 获取试卷题目
        List<TestPaperQuestion> testPaperQuestions = testPaperQuestionMapper.selectByExaminationPaperId(paperId);
        List<Integer> questionIds = testPaperQuestions.stream().map(TestPaperQuestion::getQuestionId).collect(Collectors.toList());
        // 获取题目信息
        List<TestQuestion> questions = testQuestionMapper.selectByIds(questionIds);
        ExaminationContent e = new ExaminationContent();
        // 设置试卷信息
        e.setId(examinationPaper.getId());
        e.setName(examinationPaper.getName());
        e.setExamduration(examinationPaper.getExamduration());
        e.setStatus(examinationPaper.getStatus());
        e.setQuestionSize(questions.size());
        // 设置题目信息
        e.setQuestions(questions);
        return Msg.success(e);
    }

    @Transactional(rollbackFor = CustomTransactionalException.class)
    public Msg submitTheTestPaper(SubmitExamForm submitExamForm) {
        // 作答记录
        ExamAnswerRecord examAnswerRecord = new ExamAnswerRecord();
        // 作答详细记录
        List<ExamAnswerDetail> examAnswerDetails = new ArrayList<>();
        // 获取试卷信息
        ExaminationPaper examinationPaper = examinationPaperMapper.selectByPrimaryKey(submitExamForm.getPaperId());
        if (examinationPaper == null) {
            return Msg.error("试卷不存在");
        }
        // 获取试卷题目
        List<TestPaperQuestion> testPaperQuestions = testPaperQuestionMapper.selectByExaminationPaperId(submitExamForm.getPaperId());
        List<Integer> questionIds = testPaperQuestions.stream().map(TestPaperQuestion::getQuestionId).collect(Collectors.toList());
        // 获取题目信息
        List<TestQuestion> questions = testQuestionMapper.selectByIds(questionIds);
        // list转map
        Map<Integer, TestQuestion> questionMap = questions.stream().collect(Collectors.toMap(TestQuestion::getId, Function.identity()));
        // 开始统计
        int totalScore = 0;
        Date date = new Date();
        List<Map<String, String>> answers = submitExamForm.getAnswers();
        for (Map<String, String> answer : answers) {
            ExamAnswerDetail temp = new ExamAnswerDetail();
            temp.setQuestionId(Integer.valueOf(answer.get("id")));
            temp.setTestPaperId(submitExamForm.getPaperId());
            temp.setUserId(submitExamForm.getUserId());
            // 得分
            int score = 0;
            TestQuestion question = questionMap.get(Integer.valueOf(answer.get("id")));
            if (question.getCorrectAnswer().equals(answer.get("options"))) {
                score = question.getScore();
                temp.setAnswerStatus(1);
            } else {
                temp.setAnswerStatus(0);
            }
            temp.setScore(score);
            temp.setAnswerContent(answer.get("options"));
            temp.setCreateTime(date);
            totalScore += score;
            examAnswerDetails.add(temp);
        }
        // 设置作答记录
        examAnswerRecord.setUserId(submitExamForm.getUserId());
        examAnswerRecord.setTestPaperId(submitExamForm.getPaperId());
        examAnswerRecord.setTotalScore(totalScore);
        examAnswerRecord.setCreateTime(new Date());
        // 插入作答记录
        if (examAnswerRecordMapper.insert(examAnswerRecord) != 1) {
            throw new CustomTransactionalException("插入作答记录失败");
        }
        // 插入作答详细记录
        if (examAnswerDetails.size() > 0) {
            if (examAnswerDetailMapper.insertBatch(examAnswerDetails) != examAnswerDetails.size()) {
                throw new CustomTransactionalException("插入作答详细记录失败");
            }
        }
        return Msg.success();
    }

    public PageVo<ExamRecord> getExamPageRecords(ExamRecordPageForm pageForm) {
        PageVo<ExamRecord> pageVo = new PageVo<ExamRecord>().setCurrentAndSize(pageForm);
        // 设置总的记录条数
        pageVo.setTotal(counterExamRecordTotalNumber(pageForm));
        // 当前查询页数
        int pageIndex = pageVo.getPageIndex();
        // 判断当前页数是否超过总页数
        pageIndex = pageIndex > pageVo.getPages() ? 1 : pageIndex;
        pageVo.setPageIndex(pageIndex);
        // 查询考试记录数据
        List<ExamAnswerRecord> recordList = examAnswerRecordMapper.selectByPage((pageIndex - 1) * pageVo.getPageSize(), pageVo.getPageSize(), pageForm.getUserId());
        List<ExamRecord> records = new ArrayList<ExamRecord>(recordList.size());
        recordList.forEach(record -> {
            ExamRecord examRecord = new ExamRecord();
            examRecord.setRecordId(record.getId());
            // 查询考试信息
            ExaminationPaper examinationPaper = examinationPaperMapper.selectByPrimaryKey(record.getTestPaperId());
            // 1- 试卷id
            examRecord.setPaperId(examinationPaper.getId());
            // 2- 试卷名称
            examRecord.setPaperName(examinationPaper.getName());
            // 查询考试详细情况
            List<ExamAnswerDetail> detailList = examAnswerDetailMapper.selectByUserIdAndPaperId(record.getUserId(), record.getTestPaperId());
            // 3- 试题数量
            examRecord.setNumberOfQuestions(detailList.size());
            // 4- 答对数量
            int correctNumber = 0;
            for (ExamAnswerDetail examAnswerDetail : detailList) {
                if (examAnswerDetail.getAnswerStatus() == 1) {
                    correctNumber++;
                }
            }
            examRecord.setNumberOfCorrectAnswers(correctNumber);
            // 5- 得分
            examRecord.setScore(record.getTotalScore());
            // 6- 考试时间
            examRecord.setExamTime(record.getCreateTime());
            records.add(examRecord);
        });
        pageVo.setRecords(records);
        return pageVo;
    }

    /**
     * 统计考试记录的数量
     */
    private Long counterExamRecordTotalNumber(ExamRecordPageForm pageForm) {
        return examAnswerRecordMapper.countExamRecordTotalNumber(pageForm.getUserId());
    }

    /**
     * 获取答题详情
     *
     * @param recordId 记录id
     * @return 答题详情
     */
    public Msg getExamRecordDetails(Integer recordId) {
        // List<ExamRecordDetail>
        // 根据记录id查询答题记录
        ExamAnswerRecord examAnswerRecord = examAnswerRecordMapper.selectByPrimaryKey(recordId);
        if (examAnswerRecord == null) {
            return Msg.error("记录不存在");
        }
        // 根据记录id查询答题详情
        List<ExamAnswerDetail> examAnswerDetails = examAnswerDetailMapper.selectByUserIdAndPaperId(examAnswerRecord.getUserId(), examAnswerRecord.getTestPaperId());
        // 提取问题id
        List<Integer> questionIds = examAnswerDetails.stream().map(ExamAnswerDetail::getQuestionId).collect(Collectors.toList());
        // 根据问题id查询问题
        List<TestQuestion> questions = testQuestionMapper.selectByIds(questionIds);
        // list转map
        Map<Integer, TestQuestion> questionMap = questions.stream().collect(Collectors.toMap(TestQuestion::getId, Function.identity()));
        // 组装返回数据
        List<ExamRecordDetail> examRecordDetails = new ArrayList<ExamRecordDetail>(examAnswerDetails.size());
        examAnswerDetails.forEach(examAnswerDetail -> {
            ExamRecordDetail examRecordDetail = new ExamRecordDetail();
            // 获取问题
            TestQuestion testQuestion = questionMap.get(examAnswerDetail.getQuestionId());
            // 复制属性
            BeanUtil.copyProperties(testQuestion, examRecordDetail, CopyOptions.create().setIgnoreNullValue(true));
            // 设置答案
            examRecordDetail.setOption(examAnswerDetail.getAnswerContent());
            // 设置答题状态
            examRecordDetail.setAnswerStatus(examAnswerDetail.getAnswerStatus());
            examRecordDetails.add(examRecordDetail);
        });
        return Msg.success(examRecordDetails);
    }

    @Getter
    @Setter
    private static class ExaminationContent extends ExaminationPaper {
        private List<TestQuestion> questions;
    }
}